/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using DaveSexton.DocProject.Resources;

namespace DaveSexton.DocProject
{
	public abstract class ProjectItemBase : IProjectItem
	{
		#region Public Properties
		public Uri Location
		{
			get
			{
				return location;
			}
		}

		public Uri BaseLocation
		{
			get
			{
				return baseLocation;
			}
		}

		public Uri RelativeLocation
		{
			get
			{
				return relativeLocation;
			}
		}

		public bool IsDirectory
		{
			get
			{
				return isDirectory;
			}
		}

		public bool IsExternal
		{
			get
			{
				return !baseLocation.IsBaseOf(location);
			}
		}

		public string BasePath
		{
			get
			{
				return baseLocation.LocalPath;
			}
		}

		public string Path
		{
			get
			{
				return location.LocalPath;
			}
		}

		public string RelativePath
		{
			get
			{
				if (relativeLocation == null)
					throw new InvalidOperationException(Errors.AbsoluteUri);
				else
					return PathFormat.MakeLocal(System.Web.HttpUtility.UrlDecode(relativeLocation.ToString()));
			}
		}

		public string RelativePathWithoutDirectorySeparator
		{
			get
			{
				string path = RelativePath;

				if (isDirectory)
					path = path.Substring(0, path.Length - 1);

				return path;
			}
		}

		public bool Exists
		{
			get
			{
				if (isDirectory)
					return System.IO.Directory.Exists(Path);
				else
					return System.IO.File.Exists(Path);
			}
		}

		public bool IsReadOnly
		{
			get
			{
				return !isDirectory && (File.GetAttributes(Path) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;
			}
			[System.Diagnostics.DebuggerHidden]
			set
			{
				if (isDirectory)
				{
					if (value)
						throw new InvalidOperationException(Resources.Errors.CannotSetDirectoryReadOnly);
					else
						return;
				}

				string path = Path;

				FileAttributes attributes = File.GetAttributes(path);

				if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
				{
					if (!value)
					{
						attributes &= ~FileAttributes.ReadOnly;
						File.SetAttributes(path, attributes);
					}
				}
				else if (value)
				{
					attributes |= FileAttributes.ReadOnly;
					File.SetAttributes(path, attributes);
				}
			}
		}

		public abstract bool IsVisible { get; }

		public abstract IProjectItem DependentUpon { get; set; }
		#endregion

		#region Private / Protected
		private readonly Uri baseLocation, relativeLocation, location;
		private readonly bool isDirectory;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="ProjectItemBase" /> class for derived classes.
		/// </summary>
		protected ProjectItemBase(Uri baseLocation, string path)
			: this(baseLocation, path, false)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="ProjectItemBase" /> class for derived classes.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings")]
		protected ProjectItemBase(Uri baseLocation, string path, bool forceDirectory)
		{
			if (baseLocation == null)
				throw new ArgumentNullException("baseLocation");

			if (!baseLocation.IsAbsoluteUri)
				throw new InvalidOperationException(Errors.UriMustBeNullOrAbsolute);

			if (path == null)
				throw new ArgumentNullException("path");

			path = PathFormat.MakeLocal(path);

			if (path.Length == 0)
				throw new ArgumentException(Errors.EmptyString, "path");

			this.baseLocation = baseLocation;

			if (forceDirectory)
			{
				isDirectory = true;
				path = PathFormat.EnsureDirectory(path);
			}
			else
				isDirectory = PathFormat.IsDirectory(path);

			// NOTE: If path is absolute then baseLocation will be ignored by the Uri class.
			location = new Uri(baseLocation, path);

			if (!System.IO.Path.IsPathRooted(path))
				relativeLocation = new Uri(path, UriKind.Relative);
			else if (baseLocation.IsBaseOf(location))
				relativeLocation = baseLocation.MakeRelativeUri(location);
		}
		#endregion

		#region Methods
		public abstract IProjectItem MakeDependencyFor(string path);

		public abstract void Checkout();

		public virtual void EnsureExists()
		{
			string path = Path;

			if (isDirectory)
			{
				if (!System.IO.Directory.Exists(path))
					System.IO.Directory.CreateDirectory(path);
			}
			else if (!System.IO.File.Exists(path))
				throw new System.IO.FileNotFoundException(Errors.ProjectFileCannotBeCreated, path);
		}

		public virtual void Refresh()
		{
			Hide();

			if (Exists)
				Show();
		}

		public abstract bool Hide();

		public abstract void Show();

		public abstract void Open();
		
		public abstract void Delete();

		public override string ToString()
		{
			return location.ToString();
		}
		#endregion
	}
}
